package ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Calendar;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import data.Event;
import data.EventDateTime;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

import core.Utility;

import ui.table.EventTable;
import java.awt.event.KeyEvent;


public class AppWindow implements PropertyChangeListener
{

	private AbstractAction listDownAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			if ((e.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
				eventList.setSelectedMultipleIndexDown();	
			} else {
				eventList.setSelectedIndexDown();
			}
		}
	};
	
	private AbstractAction listUpAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			if ((e.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
				eventList.setSelectedMultipleIndexUp();	
			} else {
				eventList.setSelectedIndexUp();
			}
		}
	};

	private AbstractAction listTabShiftUpAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
				eventList.setSelectedIndexUp();
		}
	};
	
	
	private AbstractAction tickAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			multipleEventsAction("toggle tick");
		}
	};

	private AbstractAction starAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			multipleEventsAction("toggle star");
		}
	};
	
	private AbstractAction deleteAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			multipleEventsAction("delete");
		}
	};

	private AbstractAction editAction = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			System.out.println("edit");
			//multipleEventsAction("edit");
		}
	};	
	
	private AbstractAction showEventDetails = new AbstractAction() {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = eventList.getSelectedIndex();
			if(row!=-1) {
				Event event =  (Event) eventList.getValueAtIndex(row, 1);
				showEventDetails(event);
			}
		}
	};
	
	private JFrame frame;
	private JTextField commandBox;

	private Dimension panelBoxSize = new Dimension(420, 49);
	private Point panelBoxLocation = new Point(0, 0);
	private Rectangle commandBoxBounds = new Rectangle(69, 0, 351, 48);

	private Dimension frameSize = new Dimension(420, 82);
	private Point frameLocation = new Point(112, 60);

	private Dimension panelListSize = new Dimension(420, 162);
	private Point panelListLocation = new Point(0, panelBoxSize.height);

	private Dimension frameSizeBox = panelBoxSize;	
	private Dimension frameSizeFull = new Dimension(panelBoxSize.width,
			panelBoxSize.height + panelListSize.height);

	private EventTable eventList;
	private View view;
	private Event[] resultEvents;
	private JPanel panelBox;
	private JPanel panelList;
	private JScrollPane scrollPane;
	private static final Image taskbarIcon = createImage("images/icon.png");
	private static final ImageIcon leftButtonIcon = createImageIcon("images/icon1.png");
	private JPanel optionpane;
	private JPanel passwordpane;
	private JPanel helpScreen;

	/**
	 * @wbp.nonvisual location=21,139
	 */

	public AppWindow() {
		initialize();
	}

	private static BufferedImage createImage(String path) {
		java.net.URL imgURL = AppWindow.class.getResource(path);
		if (imgURL != null) {
			try {
				return ImageIO.read(imgURL);
			} catch (IOException e) {
				System.err.println("Image not found");
				e.printStackTrace();
			}
		} else {
			System.err.println("Couldn't find file: " + path);
			return null;
		}
		return null;
	}

	private void initialize() {
		Border raisedbevel = BorderFactory.createRaisedBevelBorder();
		Border loweredbevel = BorderFactory.createLoweredBevelBorder();
		Border compound = BorderFactory.createCompoundBorder(
				raisedbevel, loweredbevel);

		frame = new JFrame();
		frame.setUndecorated(true);
		frame.getContentPane().setBackground(new Color(248, 248, 255));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		frame.setSize(frameSizeBox);
		frame.setLocation(frameLocation);
		frame.setIconImage(taskbarIcon );
		frame.setAlwaysOnTop(true);
		Border blackline;
		blackline = BorderFactory.createLineBorder(Color.black);
		TitledBorder title = BorderFactory.createTitledBorder(blackline,
				"Reminder");
		title.setTitleJustification(TitledBorder.CENTER);
		eventList = new EventTable();

		panelBox = new JPanel();
		panelBox.setBackground(new Color(255, 255, 255));
		panelBox.setBorder(compound);
		panelBox.setBackground(new Color(255, 255, 255));

		panelBox.setLocation(panelBoxLocation);
		panelBox.setSize(panelBoxSize);
		panelBox.setLayout(null);
		optionpane = new EventNotePanel(frame);
		
		optionpane.setBorder(new LineBorder(new Color(0, 0, 139), 2, true));
		optionpane.setBackground(Color.white);
		optionpane.setForeground(Color.BLUE);

		commandBox = new WindowCommandBox();
		commandBox.setBounds(commandBoxBounds );
		commandBox.setFont(new Font("Arial", Font.BOLD, 16));
		commandBox.setBackground(new Color(255, 255, 255));
		commandBox.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		commandBox.setBorder(new LineBorder(new Color(0, 0, 139), 2, true));
		commandBox.addPropertyChangeListener(this);
		panelBox.add(commandBox);

		JLabel lblNewLabel = new JLabel(leftButtonIcon);
		lblNewLabel.setBorder(new LineBorder(new Color(0, 0, 139), 2));
		lblNewLabel.setBounds(0, 0, 77, 48);
		panelBox.add(lblNewLabel);

		frame.getContentPane().add(panelBox);

		panelList = new JPanel();
		panelList.setVisible(false);

		frame.getContentPane().add(panelList);

		((JComponent)frame.getContentPane()).setBorder(compound);
		scrollPane = new JScrollPane(eventList.getComponent());
		scrollPane.setBorder(new LineBorder(new Color(0, 0, 139), 2, true));;
		scrollPane.setVisible(false);
		frame.getContentPane().add(scrollPane);
		scrollPane.setForeground(new Color(0, 0, 139));
		scrollPane.setFont(new Font("Arial", Font.BOLD, 16));
		scrollPane.setBackground(Color.WHITE);

		//scrollPane.setBounds(112, 109, 420, 163);

		scrollPane.setSize(panelListSize); //(eventList.getRowHeight());
		scrollPane.setLocation(panelListLocation);
		setupInputMaps();
		frame.setVisible(true);
	}

	private void setupInputMaps() {
		KeyEventDispatcher dispatcher = new ProgramKeyManager();
		System.out.println(commandBox.getFocusTraversalKeysEnabled());
		panelBox.setFocusTraversalKeysEnabled(false);
		frame.getContentPane().setFocusTraversalKeysEnabled(false);
		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
//		KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
//		KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
//		KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, Collections.EMPTY_SET);
//		KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, Collections.EMPTY_SET);

		setupInputMap(commandBox.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
		setupInputMap(eventList.getComponent().getInputMap());
		
		setupActionMaps(commandBox.getActionMap());
		setupActionMaps(eventList.getComponent().getActionMap());

		commandBox.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_MASK), "listDownAction");
		commandBox.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_MASK), "listUpAction");
		
		eventList.getComponent().getActionMap().put("showEventDetails", showEventDetails);
		eventList.getComponent().getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "showEventDetails");
	}

	private void setupActionMaps(ActionMap actionMap) {
		actionMap.put("listDownAction", listDownAction);
		actionMap.put("listUpAction", listUpAction);
		actionMap.put("listTabShiftUpAction", listTabShiftUpAction);
		actionMap.put("starAction", starAction);
		actionMap.put("tickAction", tickAction);
		actionMap.put("deleteAction", deleteAction);		
		actionMap.put("editAction", editAction);
	}

	private void setupInputMap(InputMap inputMap) {
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK), "starAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK), "tickAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "listDownAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "listDownAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "listUpAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_MASK, false), "listTabShiftUpAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "deleteAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.CTRL_MASK), "deleteAction");
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_MASK), "editAction");
	}

	public void showBoxOnScreen() {
		panelBox.setVisible(false);
		panelBox.setVisible(true);
		frame.setVisible(false);
		frame.setVisible(true);
	}

	public static ImageIcon createImageIcon(String path) {
		java.net.URL imgURL = AppWindow.class.getResource(path);
		if (imgURL != null) {
			return new ImageIcon(imgURL);
		} else {
			System.err.println("Couldn't find file: " + path);
			return null;
		}
	}
	public void setBoxVisible(boolean b) {
		panelBox.setVisible(b);
		frame.setVisible(b);
	}

	public void setListVisible(boolean b) { 
		panelList.setVisible(b);
		scrollPane.setVisible(b);
		if (b) {
			frame.setSize(frameSizeFull);
		} else {
			frame.setSize(frameSizeBox);
		}
		commandBox.requestFocus();
	}

	public void showEventDetails(Event e) {
		((EventNotePanel) optionpane).setMessage(e);
		optionpane.setVisible(true);
		optionpane.setLocation(frame.getLocationOnScreen().x, frame.getLocationOnScreen().y+200);
	}
	
	public void setPasswordpaneVisible() {
		passwordpane = new PasswordField();
		passwordpane.setVisible(true);
		passwordpane.setLocation(100, 200);
		passwordpane.addPropertyChangeListener(this);
	}

    private void setHelpScreenVisible() {
		
		helpScreen = new HelpScreen();
		helpScreen.setVisible(true);
	}

	
	
	public boolean isBoxVisible() {
		return panelBox.isVisible();
	}

	public boolean isListAreaVisible() {
		return panelList.isVisible();
	}

	public void setCommandListener(PropertyChangeListener listener) {
		commandBox.addPropertyChangeListener(listener);
	}

	public void addEventsToList(Event[] resultEvents) {
		this.resultEvents = resultEvents;
		eventList.addEventsToList(resultEvents);
	}

	public JFrame getParentComponent() {
		return frame;
	}
	public void showResult() {

	}


	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		String changedProperty = evt.getPropertyName();
		if ("usernamePassword".equals(changedProperty)) {
			view.executeControllerCommand("login " + (String)evt.getNewValue());
		}
		if("deleteCommand".equals(changedProperty)) {
			int index = eventList.getSelectedIndex();
			if (index != -1) {
				multipleEventsAction("delete");
			}
		}
		if("autocompletevent".equals(changedProperty)) {
			int row = eventList.getSelectedIndex();
			if(row != -1) {
				Event e =  (Event) eventList.getValueAtIndex(row, 1);
				String eventString = toString(e);
				String userCommand = (String) evt.getNewValue();
				String userCommandType = getHead(userCommand);

				String commandExecute = userCommandType + " " + e.getId();
				view.executeControllerCommand(commandExecute);

				String autoCompleteText = userCommandType + " ";
				if (userCommandType.equals("edit")) {
					autoCompleteText += eventString;
				}
				commandBox.setText(autoCompleteText);
			} else {
				singleEventCommand((String)evt.getNewValue());
			}
		}
		if("showPasswordDialog".equals(changedProperty)) {
			setPasswordpaneVisible();
		}
		if("increaseSize".equals(changedProperty)) {
			String command = (String) evt.getNewValue();
			String n = Utility.removeFirstWord(command);
			try {
				changeSize(Integer.parseInt(n));
			} catch (NumberFormatException e) {
				view.executeControllerCommand(command);
			}
		}
		if("showDialog".equals(changedProperty)) {
			int row = eventList.getSelectedIndex();
			if(row!=-1) {
				String userCommand = (String) evt.getNewValue();
				commandBox.setText(userCommand);
				Event e =  (Event) eventList.getValueAtIndex(row, 1);
				showEventDetails(e);
			}
		}
		if("ShowHelp".equals(changedProperty)) {
			setHelpScreenVisible();
		}

		if("refreshList".equals(changedProperty)) {
			//view.executeControllerCommand((String)evt.getNewValue());
		}
	}
	private void changeSize(int n) {
		// TODO Auto-generated method stub
		if(n>=5 && n<=10) {
		panelListSize = new Dimension(420, n*40);
		scrollPane.setSize(panelListSize.width,panelListSize.height);
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		frameSizeFull = new Dimension(panelBoxSize.width,
				panelBoxSize.height + panelListSize.height);
		}
	}

	private void multipleEventsAction(String type) {
		int[] rows = eventList.getSelectedIndices();
		
		if (rows.length == 0) {
			return;
		}
		
		StringBuilder userCommand = new StringBuilder(type);
		for (int row : rows) {
			Event event =  (Event) eventList.getValueAtIndex(row, 1);
			userCommand.append(" " + event.getId());
		}
		view.executeControllerCommand(userCommand.toString());
	}

	public void updateMultipleEventsInLists(Event[] events) {
		int[] rows = eventList.getSelectedIndices();
		Event event;
		for (int i = 0; i < rows.length; i++) {
			//Update view for each element
			event = events[i];
			if (event == null) {
				eventList.removeValueAtRow(rows[i]-i);
			} else {
				eventList.setValueAtRow(rows[i], event);
			}
		}
	}

	private void singleEventCommand(String command) {
		String partialCommand = Utility.removeFirstWord(command);
		String eventId = partialCommandCheck(partialCommand);
		if(eventId != null) {
			String commandExecute = Utility.getHead(command) + " " + eventId;
			view.executeControllerCommand(commandExecute);
		}
	}
	private String partialCommandCheck(String partialCommand) {

		if(resultEvents!=null && resultEvents.length == 1) {
			return resultEvents[0].getId();
		}
		return null;
	}

	public static String getHead(String userCommand) {
		String commandTypeString = userCommand.trim().split("\\s+")[0];
		return commandTypeString;
	}
	public String toString(Event event) {

		String result = "";
		if (event.getName() != null) {
			result = event.getName();
		}
		EventDateTime defaultDateTime = new EventDateTime();
		if (!(event.getStart().getTime().equals(defaultDateTime))) {
			int hourTime;
			int minTime;
			String time = "";
			hourTime = event.getStart().get(Calendar.HOUR);
			minTime = event.getStart().get(Calendar.MINUTE);

			String suffix = event.getStart().getTime().getDisplayName(Calendar.AM_PM, Calendar.SHORT).toLowerCase();
			time+=hourTime;
			if (minTime!=0) {
				time+="."+minTime;
			}

			result += " " + "at " + time + suffix;
		}
		if(event.getDuration()!=0) {
			int min[] = Utility.minutesToHour(event.getDuration());
			if(min[1]==0&& min[0]!=0) {
				result+=" "+"for " +min[0]+"hrs";
			}
			else if (min[0]==0&&min[1]!=0)
			 {
			result+=" "+"for "+min[1]+"mins";
			}
			else {
				result+=" "+"for "+min[0]+"."+min[1]+"hrs";
			}
		}
		if(!(event.getStart().getDate().equals(defaultDateTime))) {
			int day = event.getStart().get(Calendar.DAY_OF_MONTH);
			String month=event.getStart().getDate().getDisplayName(Calendar.MONTH,Calendar.SHORT);

			result += " " + "on " + day + Utility.getDaySuffix(day) + " " + month;
			int year = event.getStart().getDate().get(Calendar.YEAR);
			if (year != EventDateTime.current().get(Calendar.YEAR)) {
				result += ", " + year;
			}
		}
		if (event.getLabels() != null) {
			String label ="";
			for(int i=0;i<event.getLabels().size();i++) {
				label +=event.getLabels().get(i);
				System.out.print(label);
			}
			result += " " + "@" + label;
		}
		return result;
	}
	public void setParent(View view) {
		this.view = view;
	}
	public int getIndex() {
		System.out.println(eventList.getSelectedIndex());
		return eventList.getSelectedIndex();
	}


	public Component getBox() {
		return panelBox;
	}

	public void setBoxFocus() {
		commandBox.requestFocusInWindow();
		commandBox.requestFocus();
	}

	public void setOnlyBoxVisible() {
		setBoxVisible(true);
		setListVisible(false);
		frame.setSize(frameSizeBox);
	}

	public Dimension getBoxSize() {
		return panelBoxSize;
	}

	public Point getFrameLocation() {
		return frame.getLocation();
	}

	public void setButtonListener(ActionListener listener) {
		eventList.setButtonListener(listener);
	}

	public void clearBoxText() {
		commandBox.setText("");
	}
}
